from typing import List, Tuple, Optional
from backend.models.request_log import LoginHistory
from datetime import datetime, timedelta
import re
import httpx

class LoginHistoryService:
    @staticmethod
    async def create_login_history(user_id: int, ip_address: str, user_agent: str, status: str = "成功"):
        """
        创建登录历史记录
        """
        # 解析浏览器信息
        browser = LoginHistoryService._parse_browser(user_agent)
        
        # 解析操作系统
        os_info = LoginHistoryService._parse_os(user_agent)
        
        # 解析设备信息
        device = LoginHistoryService._parse_device(user_agent)
        
        # 尝试获取位置信息（可能会很慢，可以考虑异步处理）
        location = await LoginHistoryService._get_location(ip_address)
        
        # 创建登录历史
        history = await LoginHistory.create(
            user_id=user_id,
            ip_address=ip_address,
            user_agent=user_agent,
            browser=browser,
            os=os_info,
            device=device,
            location=location,
            status=status
        )
        
        return history
    
    @staticmethod
    async def get_login_history(
        page: int = 1, 
        limit: int = 10, 
        username: Optional[str] = None,
        ip: Optional[str] = None,
        status: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None
    ) -> Tuple[List[LoginHistory], int]:
        """
        获取登录历史记录，支持分页和筛选
        """
        # 构建查询
        query = LoginHistory.all().prefetch_related("user")
        
        # 根据筛选条件调整查询
        if username:
            query = query.filter(user__username__contains=username)
        
        if ip:
            query = query.filter(ip_address__contains=ip)
            
        if status:
            query = query.filter(status=status)
            
        if start_date:
            try:
                # 检查是否已包含时间部分
                if " " in start_date and len(start_date) > 10:
                    # 日期字符串已包含时间部分，直接解析
                    start_datetime = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
                else:
                    # 仅包含日期，添加默认的开始时间 00:00:00
                    start_datetime = datetime.strptime(f"{start_date} 00:00:00", "%Y-%m-%d %H:%M:%S")
                query = query.filter(login_time__gte=start_datetime)
            except (ValueError, TypeError) as e:
                print(f"登录历史日期解析错误(start_date): {e}")
            
        if end_date:
            try:
                # 检查是否已包含时间部分
                if " " in end_date and len(end_date) > 10:
                    # 日期字符串已包含时间部分，直接解析
                    end_datetime = datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S")
                else:
                    # 仅包含日期，添加默认的结束时间 23:59:59
                    end_datetime = datetime.strptime(f"{end_date} 23:59:59", "%Y-%m-%d %H:%M:%S")
                query = query.filter(login_time__lte=end_datetime)
            except (ValueError, TypeError) as e:
                print(f"登录历史日期解析错误(end_date): {e}")
        
        # 获取总数
        total = await query.count()
        
        # 分页
        skip = (page - 1) * limit
        records = await query.offset(skip).limit(limit).order_by("-login_time")
        
        return records, total
    
    @staticmethod
    async def get_stats():
        """
        获取登录统计信息
        """
        # 获取当前日期
        today = datetime.now().date()
        week_start = today - timedelta(days=today.weekday())
        month_start = datetime(today.year, today.month, 1).date()
        
        # 今日登录次数
        today_start = datetime.combine(today, datetime.min.time())
        today_end = datetime.combine(today, datetime.max.time())
        today_logins = await LoginHistory.filter(
            login_time__gte=today_start, 
            login_time__lte=today_end
        ).count()
        
        # 本周登录次数
        week_start_dt = datetime.combine(week_start, datetime.min.time())
        week_logins = await LoginHistory.filter(login_time__gte=week_start_dt).count()
        
        # 本月登录次数
        month_start_dt = datetime.combine(month_start, datetime.min.time())
        month_logins = await LoginHistory.filter(login_time__gte=month_start_dt).count()
        
        # 登录失败次数
        failed_logins = await LoginHistory.filter(status="失败").count()
        
        return {
            "todayLogins": today_logins,
            "weekLogins": week_logins,
            "monthLogins": month_logins,
            "failedLogins": failed_logins
        }
    
    @staticmethod
    async def get_trend_data(trend_type: str = "week"):
        """
        获取登录趋势数据
        """
        today = datetime.now().date()
        
        if trend_type == "week":
            # 过去7天
            days = 7
            start_date = today - timedelta(days=days-1)
        else:
            # 过去30天
            days = 30
            start_date = today - timedelta(days=days-1)
        
        # 初始化日期数据
        dates = []
        success_counts = []
        fail_counts = []
        
        # 查询每天的数据
        for i in range(days):
            current_date = start_date + timedelta(days=i)
            date_start = datetime.combine(current_date, datetime.min.time())
            date_end = datetime.combine(current_date, datetime.max.time())
            
            # 成功登录次数
            success_count = await LoginHistory.filter(
                login_time__gte=date_start, 
                login_time__lte=date_end,
                status="成功"
            ).count()
            
            # 失败登录次数
            fail_count = await LoginHistory.filter(
                login_time__gte=date_start, 
                login_time__lte=date_end,
                status="失败"
            ).count()
            
            dates.append(current_date.strftime("%m-%d"))
            success_counts.append(success_count)
            fail_counts.append(fail_count)
        
        return {
            "dates": dates,
            "success": success_counts,
            "fail": fail_counts
        }
    
    @staticmethod
    def _parse_browser(user_agent: str) -> str:
        """解析浏览器信息"""
        ua = user_agent.lower()
        if "edg" in ua:
            return "Edge"
        if "chrome" in ua and "chromium" not in ua and "edg" not in ua:
            return "Chrome"
        if "safari" in ua and "chrome" not in ua:
            return "Safari"
        if "firefox" in ua:
            return "Firefox"
        if "opera" in ua or "opr" in ua:
            return "Opera"
        if "msie" in ua or "trident" in ua:
            return "IE"
        return "其他"
    
    @staticmethod
    def _parse_os(user_agent: str) -> str:
        """解析操作系统信息"""
        ua = user_agent.lower()
        if "windows" in ua:
            match = re.search(r"windows nt (\d+\.\d+)", ua)
            if match:
                ver = match.group(1)
                versions = {
                    "10.0": "Windows 10",
                    "6.3": "Windows 8.1",
                    "6.2": "Windows 8",
                    "6.1": "Windows 7",
                    "6.0": "Windows Vista",
                    "5.2": "Windows XP",
                    "5.1": "Windows XP",
                    "5.0": "Windows 2000"
                }
                return versions.get(ver, f"Windows ({ver})")
            return "Windows"
        if "mac os x" in ua:
            match = re.search(r"mac os x (\d+[._]\d+[._]?\d*)", ua)
            if match:
                ver = match.group(1).replace("_", ".")
                return f"macOS {ver}"
            return "macOS"
        if "linux" in ua:
            if "android" in ua:
                match = re.search(r"android (\d+\.\d+)", ua)
                if match:
                    return f"Android {match.group(1)}"
                return "Android"
            return "Linux"
        if "ios" in ua or "iphone" in ua or "ipad" in ua:
            match = re.search(r"os (\d+[._]\d+)", ua)
            if match:
                ver = match.group(1).replace("_", ".")
                return f"iOS {ver}"
            return "iOS"
        return "其他"
    
    @staticmethod
    def _parse_device(user_agent: str) -> str:
        """解析设备信息"""
        ua = user_agent.lower()
        if "iphone" in ua:
            return "iPhone"
        if "ipad" in ua:
            return "iPad"
        if "android" in ua:
            if "mobile" in ua:
                return "Android手机"
            return "Android设备"
        if "windows" in ua:
            if "mobile" in ua:
                return "Windows Phone"
            return "电脑"
        if "mac" in ua:
            return "Mac电脑"
        return "未知设备"
    
    @staticmethod
    async def _get_location(ip: str) -> str:
        """通过IP获取地理位置"""
        # 内网IP直接返回
        if ip.startswith(("10.", "172.", "192.168.", "127.")):
            return "内网IP"
        
        try:
            # 使用第三方IP地址API
            async with httpx.AsyncClient(timeout=3.0) as client:
                response = await client.get(f"http://ip-api.com/json/{ip}?lang=zh-CN")
                if response.status_code == 200:
                    data = response.json()
                    if data.get("status") == "success":
                        country = data.get("country", "")
                        region = data.get("regionName", "")
                        city = data.get("city", "")
                        return f"{country} {region} {city}".strip()
        except Exception:
            pass
        
        return "未知位置"